// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: listener code decoupling
// feature: add SetTrustRemoteEndpoint API to dispatcherReader and add locator to dispatcherWriter
// feature: DServer support simple entity
// feature: modify parameter of dispatcher api Add guid and topicname for dsf
// feature: provide query interfaces
// feature: develop dispatcher
// feature: content filter topic
// feature: discovery support client and server
// feature: support message brief record
// feature: dds support get remote participant vbs version and rm some print
// ------------------------------------------------------------------

#include <edds/rtps/Endpoint.h>
#include <edds/rtps/participant/RTPSParticipant.h>
#include <rtps/participant/RTPSParticipantImpl.h>
#include <edds/rtps/writer/RTPSWriter.h>
#include <edds/rtps/reader/RTPSReader.h>

namespace evbs {
namespace ertps {
namespace rtps {

RTPSParticipant::RTPSParticipant(RTPSParticipantImpl* pimpl) : mp_impl(pimpl) {}

RTPSParticipant::~RTPSParticipant() {
    mp_impl = nullptr;
}

const GUID_t& RTPSParticipant::getGuid() const {
    return mp_impl->getGuid();
}

void RTPSParticipant::announceRTPSParticipantState() {
    return mp_impl->announceRTPSParticipantState();
}

void RTPSParticipant::stopRTPSParticipantAnnouncement() {
    return mp_impl->stopRTPSParticipantAnnouncement();
}

void RTPSParticipant::resetRTPSParticipantAnnouncement() {
    return mp_impl->resetRTPSParticipantAnnouncement();
}

bool RTPSParticipant::startRTPSParticipantInitialAnnouncement(uint32_t count, ertps::Duration_t period) {
    return mp_impl->startRTPSParticipantInitialAnnouncement(count, period);
}

bool RTPSParticipant::newRemoteWriterDiscovered(const GUID_t& pguid, int16_t userDefinedId) {
    return mp_impl->newRemoteEndpointDiscovered(pguid, userDefinedId, WRITER);
}

bool RTPSParticipant::newRemoteReaderDiscovered(const GUID_t& pguid, int16_t userDefinedId) {
    return mp_impl->newRemoteEndpointDiscovered(pguid, userDefinedId, READER);
}

uint32_t RTPSParticipant::getRTPSParticipantID() const {
    return mp_impl->getRTPSParticipantID();
}

bool RTPSParticipant::registerWriter(vbs::dispatcher::SubstrateWriter* Writer, const BaseTopicAttributes& topicAtt,
                                     const BaseWriterQos& wqos,
                                     const vbsutil::xmlparser::ContentFilterProperty* content_filter) {

    // 尝试进行引用的 dynamic_cast 转换
    const TopicAttributes& topicAtt_ = dynamic_cast<const TopicAttributes&>(topicAtt);
    const WriterQos& wqos_ = dynamic_cast<const WriterQos&>(wqos);

    return mp_impl->registerWriter(static_cast<RTPSWriter*>(Writer), topicAtt_, wqos_, content_filter);
}

bool RTPSParticipant::registerReader(vbs::dispatcher::SubstrateReader* Reader, const BaseTopicAttributes& topicAtt,
                                     const BaseReaderQos& rqos,
                                     const vbsutil::xmlparser::ContentFilterProperty* content_filter) {

    // 尝试进行引用的 dynamic_cast 转换
    const TopicAttributes& topicAtt_ = dynamic_cast<const TopicAttributes&>(topicAtt);
    const ReaderQos& rqos_ = dynamic_cast<const ReaderQos&>(rqos);

    return mp_impl->registerReader(static_cast<RTPSReader*>(Reader), topicAtt_, rqos_, content_filter);
}

void RTPSParticipant::update_attributes(const RTPSParticipantAttributes& patt) {
    mp_impl->update_attributes(patt);
}

bool RTPSParticipant::updateWriter(vbs::dispatcher::SubstrateWriter* Writer, const BaseTopicAttributes& topicAtt,
                                   const BaseWriterQos& wqos,
                                   const vbsutil::xmlparser::ContentFilterProperty* content_filter, bool notify) {

    // 尝试进行引用的 dynamic_cast 转换
    const TopicAttributes& topicAtt_ = dynamic_cast<const TopicAttributes&>(topicAtt);
    const WriterQos& wqos_ = dynamic_cast<const WriterQos&>(wqos);

    return mp_impl->updateLocalWriter(static_cast<RTPSWriter*>(Writer), topicAtt_, wqos_, content_filter, notify);
}

bool RTPSParticipant::updateReader(vbs::dispatcher::SubstrateReader* Reader, const BaseTopicAttributes& topicAtt,
                                   const BaseReaderQos& rqos,
                                   const vbsutil::xmlparser::ContentFilterProperty* content_filter, bool notify) {

    // 尝试进行引用的 dynamic_cast 转换
    const TopicAttributes& topicAtt_ = dynamic_cast<const TopicAttributes&>(topicAtt);
    const ReaderQos& rqos_ = dynamic_cast<const ReaderQos&>(rqos);

    return mp_impl->updateLocalReader(static_cast<RTPSReader*>(Reader), topicAtt_, rqos_, content_filter, notify);
}

std::vector<std::string> RTPSParticipant::getParticipantNames() const {
    return mp_impl->getParticipantNames();
}

std::string RTPSParticipant::prinfParticipantNames() const {
    std::string s = "";
    for (const auto& str : mp_impl->getParticipantNames()) {
        s += str;
        s += " ";
    }
    return s;
}

const RTPSParticipantAttributes& RTPSParticipant::getRTPSParticipantAttributes() const {
    return mp_impl->getRTPSParticipantAttributes();
}

uint32_t RTPSParticipant::getMaxMessageSize() const {
    return mp_impl->getMaxMessageSize();
}

uint32_t RTPSParticipant::getMaxDataSize() const {
    return mp_impl->getMaxDataSize();
}

ResourceEvent& RTPSParticipant::get_resource_event() const {
    return mp_impl->getEventResource();
}

WLP* RTPSParticipant::wlp() const {
    return mp_impl->wlp();
}

edds::dds::builtin::LookupManager* RTPSParticipant::lookup_manager() const {
    return mp_impl->lookup_manager();
}

bool RTPSParticipant::get_new_entity_id(EntityId_t& entityId) {
    return mp_impl->get_new_entity_id(entityId);
}

void RTPSParticipant::set_check_type_function(std::function<bool(const std::string&)>&& check_type) {
    mp_impl->set_check_type_function(std::move(check_type));
}

void RTPSParticipant::set_listener(vbs::common::ParticipantListener* listener) {
    mp_impl->set_listener(listener);
}

uint32_t RTPSParticipant::get_domain_id() const {
    return mp_impl->get_domain_id();
}

void RTPSParticipant::enable() {
    mp_impl->enable();
}

bool RTPSParticipant::ignore_participant(const GuidPrefix_t& participant_guid) {
    return mp_impl->ignore_participant(participant_guid);
}

bool RTPSParticipant::ignore_writer(const GUID_t& /*writer_guid*/) {  // LCOV_EXCL_START
    return false;
}

bool RTPSParticipant::ignore_reader(const GUID_t& /*reader_guid*/) {
    return false;
}  // LCOV_EXCL_STOP

#if HAVE_SECURITY

bool RTPSParticipant::is_security_enabled_for_writer(const WriterAttributes& writer_attributes) {
    return mp_impl->is_security_enabled_for_writer(writer_attributes);
}

bool RTPSParticipant::is_security_enabled_for_reader(const ReaderAttributes& reader_attributes) {
    return mp_impl->is_security_enabled_for_reader(reader_attributes);
}

#endif  // if HAVE_SECURITY

EvbsVersion_t RTPSParticipant::get_remote_evbsversion() {
    return mp_impl->get_remote_evbsversion();
}

const std::vector<RTPSWriter*>& RTPSParticipant::getAllWriters() const {
    return mp_impl->getAllWriters();
}

const std::vector<RTPSReader*>& RTPSParticipant::getAllReaders() const {
    return mp_impl->getAllReaders();
}

vbs::dispatcher::SubstrateWriter* RTPSParticipant::create_writer(GUID_t guid, vbs::BaseWriterAttributes& watt,
                                                                 std::string /*topic_name*/, std::string /*topic_type*/,
                                                                 std::shared_ptr<IPayloadPool>& payload_pool,
                                                                 std::shared_ptr<IChangePool>& change_pool,
                                                                 WriterHistory* history, WriterListener* listener,
                                                                 Locator_t* /*local_loc*/) {
    RTPSWriter* writer;
    WriterAttributes& watt_ = static_cast<WriterAttributes&>(watt);

    if (!change_pool && !payload_pool) {
        if (mp_impl->createWriter(&writer, watt_, history, listener, guid.entityId)) {
            return dynamic_cast<vbs::dispatcher::SubstrateWriter*>(writer);
        }
    } else {
        if (mp_impl->createWriter(&writer, watt_, payload_pool, change_pool, history, listener, guid.entityId)) {
            return dynamic_cast<vbs::dispatcher::SubstrateWriter*>(writer);
        }
    }
    return nullptr;
}

vbs::dispatcher::SubstrateReader* RTPSParticipant::create_reader(GUID_t guid, vbs::BaseReaderAttributes& ratt,
                                                                 std::string /*topic_name*/, std::string /*topic_type*/,
                                                                 std::shared_ptr<IChangePool>& change_pool,
                                                                 ReaderHistory* history, ReaderListener* listener,
                                                                 Locator_t* /*local_loc*/) {
    RTPSReader* reader;
    ReaderAttributes& ratt_ = static_cast<ReaderAttributes&>(ratt);

    if (!change_pool) {
        if (mp_impl->createReader(&reader, ratt_, history, listener, guid.entityId)) {
            return dynamic_cast<vbs::dispatcher::SubstrateReader*>(reader);
        }
    } else {
        if (mp_impl->createReader(&reader, ratt_, change_pool, history, listener, guid.entityId)) {
            return dynamic_cast<vbs::dispatcher::SubstrateReader*>(reader);
        }
    }
    return nullptr;
}

bool RTPSParticipant::delete_writer(vbs::dispatcher::SubstrateWriter* writer) {
    return mp_impl->deleteUserEndpoint((static_cast<RTPSWriter*>(writer))->getGuid());
}

bool RTPSParticipant::delete_reader(vbs::dispatcher::SubstrateReader* reader) {
    return mp_impl->deleteUserEndpoint((static_cast<RTPSReader*>(reader))->getGuid());
}

bool RTPSParticipant::RegisterTransport(uint32_t type) {
    return mp_impl->RegisterTransport(static_cast<vbs::transport::TransmitorType>(type));
    //重新更新proxy的locator信息
}

// @brief Check if the transport is registered and the user transport is registered
// @param type The type of the transport
// @return True if the transport is registered and the user transport is registered, false otherwise
bool RTPSParticipant::bTransportRegistered(uint32_t type) {
    // only check UDS and UDP, if check other transport, return false
    if (static_cast<vbs::transport::TransmitorType>(type) != vbs::transport::TransmitorType::TRANSMITOR_TYPE_UDS &&
        static_cast<vbs::transport::TransmitorType>(type) != vbs::transport::TransmitorType::TRANSMITOR_TYPE_UDP) {
        return false;
    }
    return (mp_impl->bTransportRegistered(static_cast<vbs::transport::TransmitorType>(type)) &&
            mp_impl->registed_user_transport(static_cast<vbs::RemoteEndpointInfo::LocatorType>(type)));
}

ReturnCode_t RTPSParticipant::assert_liveliness(vbs::dispatcher::SubstrateWriter* writer) {
    return mp_impl->assert_liveliness(static_cast<RTPSWriter*>(writer));
}

ReturnCode_t RTPSParticipant::assert_liveliness() {
    return mp_impl->assert_liveliness();
}

std::string RTPSParticipant::get_db_info(bool log_record) {
    return mp_impl->get_db_info(log_record);
}

// Get all the participants in DataBase
bool RTPSParticipant::get_participants_in_db(std::vector<GuidPrefix_t>& prefix_list) const {
    return mp_impl->get_participants_in_db(prefix_list);
}

// Get the participant info by guid_prefix
bool RTPSParticipant::get_participant_info(const GuidPrefix_t& prefix, DiscoveryParticipantInfo& part_info) const {
    return mp_impl->get_participant_info(prefix, part_info);
}

// Get the reader info by guid
bool RTPSParticipant::get_reader_info(const GUID_t& reader_guid, DiscoveryEndpointInfo& reader_info) const {
    return mp_impl->get_reader_info(reader_guid, reader_info);
}

// Get the writer info by guid
bool RTPSParticipant::get_writer_info(const GUID_t& writer_guid, DiscoveryEndpointInfo& writer_info) const {
    return mp_impl->get_writer_info(writer_guid, writer_info);
}

bool RTPSParticipant::get_topic_names(std::vector<std::string>& topic_list) const {
    return mp_impl->get_topic_names(topic_list);
}

bool RTPSParticipant::has_writer(const std::string& topic_name) const {
    return mp_impl->has_writer(topic_name);
}

bool RTPSParticipant::has_reader(const std::string& topic_name) const {
    return mp_impl->has_reader(topic_name);
}

bool RTPSParticipant::get_writer_of_topic(const std::string& topic_name,
                                          std::vector<DiscoveryEndpointInfo>& writer_info_list) const {
    return mp_impl->get_writer_of_topic(topic_name, writer_info_list);
}

bool RTPSParticipant::get_reader_of_topic(const std::string& topic_name,
                                          std::vector<DiscoveryEndpointInfo>& reader_info_list) const {
    return mp_impl->get_reader_of_topic(topic_name, reader_info_list);
}

bool RTPSParticipant::has_participant(const std::string& participant_name) const {
    return mp_impl->has_participant(participant_name);
}

bool RTPSParticipant::get_participant_of_name(const std::string& participant_name,
                                              DiscoveryParticipantInfo& part_info) const {
    return mp_impl->get_participant_of_name(participant_name, part_info);
}

} /* namespace rtps */
} /* namespace ertps */
} /* namespace evbs */
